package com.mika.music.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mika.music.constants.Constant;
import com.mika.music.model.Music;
import com.mika.music.model.User;
import com.mika.music.service.LoveMusicService;
import com.mika.music.service.MusicService;
import com.mika.music.utils.ResponseBodyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@RestController
@RequestMapping("/lovemusic")
public class LoveMusicController {

    @Autowired
    private LoveMusicService loveMusicService;

    @Autowired
    private MusicService musicService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;


    @RequestMapping("/like")
    public ResponseBodyMessage<Boolean> like(Integer musicId, HttpServletRequest request) {
        // 检查是否登录
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
            return new ResponseBodyMessage<>(-2, "请登录后再操作", false);
        }
        User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
        Integer userId = user.getId();
        log.info("userId: " + userId + ", musicId: " + musicId);
        if (userId == null || musicId == null || userId < 1 || musicId < 1) {
            return new ResponseBodyMessage<>(-1, "userId 或 musicId 不合法", false);
        }
        // 校验音乐是否存在
        // 可以先去 redis 中找，找不到再去 mysql 中找
        String redisMusicKey = "music:info:" + musicId;
        String redisMusicStr = stringRedisTemplate.opsForValue().get(redisMusicKey);
        Music music = null;
        if (StringUtils.hasLength(redisMusicStr)) {
            try {
                music = objectMapper.readValue(redisMusicStr, Music.class);
            } catch (JsonProcessingException e) {
                log.error(e.getMessage());
            }
        } else {
            // 添加到 redis 中，将音乐
            music = musicService.getMusicById(musicId);
            if (music != null) {
                try {
                    // 将对应音乐存入 redis 中
                    String musicKey = "music:info:" + music.getId();
                    String musicname = "musicName:" + music.getTitle();
                    stringRedisTemplate.opsForValue().set(musicKey, objectMapper.writeValueAsString(music), Duration.ofDays(60));
                    stringRedisTemplate.opsForValue().set(musicname, String.valueOf(music.getId()), Duration.ofDays(60));
                    log.info("getMusics, 音乐不在 redis 中存在，需要新增音乐到 redis 中：" + music);
                } catch (JsonProcessingException e) {
                    log.error(e.getMessage());
                }
            }
        }
        if (music == null) {
            return new ResponseBodyMessage<>(-1, "曲库中没有这首歌", false);
        }


        // 1. 检查是否已经收藏过该音乐
        String redisLovedMusicKey = "lovedMusic:user:" + user.getId() + ":music:" + music.getTitle();
        String redisLovedMusicStr = stringRedisTemplate.opsForValue().get(redisLovedMusicKey);
        if (StringUtils.hasLength(redisLovedMusicStr)) {
            // 已经收藏过，就需要取消收藏
            stringRedisTemplate.delete(redisLovedMusicKey);
            Integer result = loveMusicService.deleteLoved(musicId, userId);
            stringRedisTemplate.delete(redisLovedMusicKey);
            return new ResponseBodyMessage<>(-1, "取消收藏成功", false);
        }

        Music ret = loveMusicService.checkLoved(musicId, userId);
        if (ret != null) {
            // 从 redis 中删除收藏记录
            redisLovedMusicKey = "lovedMusic:user:" + user.getId() + ":music:" + ret.getTitle();
            stringRedisTemplate.delete(redisLovedMusicKey);
            Integer result = loveMusicService.deleteLoved(musicId, userId);
            stringRedisTemplate.delete(redisLovedMusicKey);
            return new ResponseBodyMessage<>(-1, "取消收藏成功", false);
        }
        // 2. 添加音乐至收藏列表
        Integer result = loveMusicService.insert(userId, musicId);
        if (result > 0) {
            return new ResponseBodyMessage<>(200, null, true);
        }
        return new ResponseBodyMessage<>(-1, "收藏失败", false);
    }

    // 查找指定用户的收藏列表中的指定歌曲
    @RequestMapping("/get")
    public ResponseBodyMessage<List<Music>> getMusic(String musicName, HttpServletRequest request) {
        // 检查是否登录
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
            return new ResponseBodyMessage<>(-2, "请登录后再操作", null);
        }

        User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
        Integer userId = user.getId();
        log.info("userId: " + userId);
        if (userId == null || userId < 1) {
            return new ResponseBodyMessage<>(-1, "userId 或 musicId 不合法", null);
        }

        // 如果歌名为空，则查询所有列表
        if (!StringUtils.hasLength(musicName)) {
            return new ResponseBodyMessage<>(200, null, loveMusicService.getLovedMusics(userId));
        }
        // TODO 如果歌名为不空，就可以根据 key:"lovedMusic:user:1:music:*蒼月的懺悔詩*"  value:"37"
        String redisLovedPatterns = "lovedMusic:user:" + user.getId() + ":music:*" + musicName + "*";
        log.info("getMusic, 根据样式: " + redisLovedPatterns + "去 redis 中扫描符合要求的 keys");
        // 指定样式以及每次扫描的数量
        ScanOptions scanOptions = ScanOptions.scanOptions().match(redisLovedPatterns).count(1000).build();
        Set<String> execute = stringRedisTemplate.execute(new RedisCallback<Set<String>>() {
            @Override
            public Set<String> doInRedis(RedisConnection connection) {

                Set<String> binaryKeys = new HashSet<>();

                Cursor<byte[]> cursor = connection.scan(scanOptions);
                while (cursor.hasNext()) {
                    binaryKeys.add(new String(cursor.next()));
                }
                return binaryKeys;
            }
        });
        log.info("getMusic, 根据音乐名查找的 keys :" + execute);
        // 再根据音乐名字获取到音乐 ID，从而获取到音乐详情
        List<String> list = stringRedisTemplate.opsForValue().multiGet(execute);
        // 得到音乐 ID 后，就是根据音乐 ID 获取音乐本体
        log.info("getMusic, 从 redis 中获取的音乐 ID 集合 musicIds: " + list);
        Set<Music> musicSet = new HashSet<>();
        List<Integer> musicIds = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (String musicId : list) {
                musicIds.add(Integer.valueOf(musicId));
                try {
                    String musicKey = "music:info:" + musicId;
                    String redisMusicStr = stringRedisTemplate.opsForValue().get(musicKey);
                    if (!StringUtils.hasLength(redisMusicStr)) {
                        Music musicTmp = musicService.getMusicById(Integer.valueOf(musicId));
                        String s = objectMapper.writeValueAsString(musicTmp);
                        stringRedisTemplate.opsForValue().set(musicKey, s);
                        String tmpName = "musicName:" + musicTmp.getTitle();
                        stringRedisTemplate.opsForValue().set(tmpName, musicId);
                    }
                    Music musicRedis = objectMapper.readValue(stringRedisTemplate.opsForValue().get(musicKey), Music.class);
                    musicSet.add(musicRedis);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }
            log.info("getMusic, 从 redis 中获取的收藏音乐集合 musics: " + musicSet);
            // TODO 然后再去 mysql 中查找剩下的收藏数据，如果有歌曲名的话
            List<Music> result = null;
            result = loveMusicService.getLovedMusicsByNameNotInIds(musicName, musicIds);
            // TODO 把对应歌曲信息添加到 redis 中
            if (result != null && result.size() != 0) {
                log.info("getMusic, 收藏音乐不在 redis 中存在，需要新增音乐到 redis 中：" + result);
                for (Music music : result) {
                    musicSet.add(music);
                    // 将对应音乐存入 redis 中
                    String redisLovedPatternsKey = "lovedMusic:user:" + user.getId() + ":music:" + music.getTitle();
                    stringRedisTemplate.opsForValue().set(redisLovedPatternsKey, String.valueOf(music.getId()));
                    stringRedisTemplate.expire(redisLovedPatternsKey, Duration.ofDays(60));

                }
            }
            return new ResponseBodyMessage<>(200, null, new ArrayList<>(musicSet));
        }


        List<Music> ret = loveMusicService.getLovedMusicsByName(musicName, userId);
        if (ret == null || ret.size() <= 0) {
            return new ResponseBodyMessage<>(-1, "没有你要找的歌曲", ret);
        }
        log.info("getMusics, 音乐不在 redis 中存在，需要新增音乐到 redis 中：" + ret);
        for (Music music : ret) {
            // 将对应音乐存入 redis 中
            String redisLovedPatternsKey = "lovedMusic:user:" + user.getId() + ":music:" + music.getTitle();
            stringRedisTemplate.opsForValue().set(redisLovedPatternsKey, String.valueOf(music.getId()));
            stringRedisTemplate.expire(redisLovedPatternsKey, Duration.ofDays(60));

        }

        return new ResponseBodyMessage<>(200, null, ret);

    }

    // 取消收藏
    @RequestMapping("/delete")
    public ResponseBodyMessage<Boolean> deleteLovedMusic(Integer musicId, HttpServletRequest request) {

        // 检查是否登录
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
            return new ResponseBodyMessage<>(-2, "请登录后再操作", null);
        }

        if (musicId == null || musicId < 1) {
            return new ResponseBodyMessage<>(-1, "userId 或 musicId 不合法", null);
        }


        User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
        Integer userId = user.getId();
        log.info("userId: " + userId);
        if (userId == null || userId < 1) {
            return new ResponseBodyMessage<>(-1, "userId 或 musicId 不合法", null);
        }

        // 将收藏记录从 redis 中删除
        // 先根据 musicId 得到 音乐本体，然后通过本体拿到歌名，再删除
        String redisMusicKey = "music:info:" + musicId;
        String redisMusicStr = stringRedisTemplate.opsForValue().get(redisMusicKey);
        String redisLovedMusicKey = "";
        try {
            if (StringUtils.hasLength(redisMusicStr)) {
                Music redisMusic = objectMapper.readValue(redisMusicStr, Music.class);
                redisLovedMusicKey = "lovedMusic:user:" + user.getId() + ":music:" + redisMusic.getTitle();
                // 然后删除
                stringRedisTemplate.delete(redisLovedMusicKey);
            }
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }
        Integer result = loveMusicService.deleteLoved(musicId, userId);
        if (result > 0) {
            if (StringUtils.hasLength(redisLovedMusicKey)) {
                stringRedisTemplate.delete(redisLovedMusicKey);
            }
            return new ResponseBodyMessage<>(200, null, true);
        }
        return new ResponseBodyMessage<>(-1, "移除音乐失败", false);

    }


}
